{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# K 紧邻算法实验"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 兼容python2和python3\n",
    "from __future__ import print_function\n",
    "\n",
    "import numpy as np\n",
    "import scipy as sp\n",
    "import pandas as pd\n",
    "import sklearn\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 实验一 求临近点\n",
    "\n",
    "已知二维空间的3个点$x_1=(1,1)^T$，$x_2=(5,1)^T$，$x_3=(4,4)^T$，试求在$p$取不同值时，$L_p$距离下$x_1$的最近邻点。\n",
    "\n",
    "**解**  因为$x_1$和$x_2$只有第二维上值不同，所以$p$为任何值时，$L_p(x_1,x_2)=4$。而\n",
    "\n",
    "$$\n",
    "L_1(x_1,x_3)=6，L_2(x_1,x_3)=4.24，L_3(x_1,x_3)=3.78，L_4(x_1,x_3)=3.57\n",
    "$$\n",
    "\n",
    "于是得到：$p$等于1或者2时，$x_2$是$x_1$的最近邻点；$p$大于等于3时，$x_3$是$x_1$的最近邻点。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "from itertools import combinations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "x1 = [1, 1]\n",
    "x2 = [5, 1]\n",
    "x3 = [4, 4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def L(x, y, p=2):\n",
    "    if len(x) == len(y) and len(x) > 1:\n",
    "        sum = 0\n",
    "        for i in range(len(x)):\n",
    "            sum += math.pow(abs(x[i] - y[i]), p)\n",
    "        return math.pow(sum, 1 / p)\n",
    "    else:\n",
    "        return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 1] - [5, 1] : 4.0\n",
      "[1, 1] - [5, 1] : 4.0\n",
      "[1, 1] - [5, 1] : 3.9999999999999996\n",
      "[1, 1] - [5, 1] : 4.0\n",
      "[1, 1] - [4, 4] : 6.0\n",
      "[1, 1] - [4, 4] : 4.242640687119285\n",
      "[1, 1] - [4, 4] : 3.7797631496846193\n",
      "[1, 1] - [4, 4] : 3.5676213450081633\n"
     ]
    }
   ],
   "source": [
    "for c in [x2, x3]:\n",
    "    for i in range(1, 5):\n",
    "        r = L(x1, c, p=i)\n",
    "        print('[1, 1] -',c,':',r)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 实验二 构造平衡Kd树"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# kd-tree每个结点中主要包含的数据结构如下\n",
    "# 节点定义\n",
    "class KdNode(object):\n",
    "    def __init__(self, dom_elt, split, left, right):\n",
    "        self.dom_elt = dom_elt  # k维向量节点(k维空间中的一个样本点)\n",
    "        self.split = split  # 整数（进行分割维度的序号）\n",
    "        self.left = left  # 该结点分割超平面左子空间构成的kd-tree\n",
    "        self.right = right  # 该结点分割超平面右子空间构成的kd-tree\n",
    "\n",
    "# Kd数\n",
    "class KdTree(object):\n",
    "    def __init__(self, data):\n",
    "        k = len(data[0])  # 数据维度\n",
    "        \n",
    "        # Kd数创建\n",
    "        def CreateNode(split, data_set):  # 按第split维划分数据集exset创建KdNode\n",
    "            if not data_set:  # 数据集为空\n",
    "                return None\n",
    "            # key参数的值为一个函数，此函数只有一个参数且返回一个值用来进行比较\n",
    "            # operator模块提供的itemgetter函数用于获取对象的哪些维的数据，参数为需要获取的数据在对象中的序号\n",
    "            #data_set.sort(key=itemgetter(split)) # 按要进行分割的那一维数据排序\n",
    "            data_set.sort(key=lambda x: x[split])\n",
    "            split_pos = len(data_set) // 2  # //为Python中的整数除法\n",
    "            median = data_set[split_pos]  # 中位数分割点\n",
    "            split_next = (split + 1) % k  # cycle coordinates\n",
    "\n",
    "            # 递归的创建kd树\n",
    "            return KdNode(\n",
    "                median,\n",
    "                split,\n",
    "                CreateNode(split_next, data_set[:split_pos]),  # 创建左子树\n",
    "                CreateNode(split_next, data_set[split_pos + 1:]))  # 创建右子树\n",
    "\n",
    "        self.root = CreateNode(0, data)  # 从第0维分量开始构建kd树,返回根节点\n",
    "\n",
    "\n",
    "# KDTree的前序遍历\n",
    "def preorder(root):\n",
    "    print(root.dom_elt)\n",
    "    if root.left:  # 节点不为空\n",
    "        preorder(root.left)\n",
    "    if root.right:\n",
    "        preorder(root.right)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对构建好的kd树进行搜索，寻找与目标点最近的样本点：\n",
    "from math import sqrt\n",
    "from collections import namedtuple\n",
    "\n",
    "# 定义一个namedtuple,分别存放最近坐标点、最近距离和访问过的节点数\n",
    "result = namedtuple(\"Result_tuple\",\n",
    "                    \"nearest_point  nearest_dist  nodes_visited\")\n",
    "\n",
    "\n",
    "def find_nearest(tree, point):\n",
    "    k = len(point)  # 数据维度\n",
    "\n",
    "    def travel(kd_node, target, max_dist):\n",
    "        if kd_node is None:\n",
    "            return result([0] * k, float(\"inf\"), 0)  # python中用float(\"inf\")和float(\"-inf\")表示正负无穷\n",
    "\n",
    "        nodes_visited = 1\n",
    "\n",
    "        s = kd_node.split  # 进行分割的维度\n",
    "        pivot = kd_node.dom_elt  # 进行分割的“轴”\n",
    "\n",
    "        if target[s] <= pivot[s]:  # 如果目标点第s维小于分割轴的对应值(目标离左子树更近)\n",
    "            nearer_node = kd_node.left  # 下一个访问节点为左子树根节点\n",
    "            further_node = kd_node.right  # 同时记录下右子树\n",
    "        else:  # 目标离右子树更近\n",
    "            nearer_node = kd_node.right  # 下一个访问节点为右子树根节点\n",
    "            further_node = kd_node.left\n",
    "\n",
    "        temp1 = travel(nearer_node, target, max_dist)  # 进行遍历找到包含目标点的区域\n",
    "\n",
    "        nearest = temp1.nearest_point  # 以此叶结点作为“当前最近点”\n",
    "        dist = temp1.nearest_dist  # 更新最近距离\n",
    "\n",
    "        nodes_visited += temp1.nodes_visited\n",
    "\n",
    "        if dist < max_dist:\n",
    "            max_dist = dist  # 最近点将在以目标点为球心，max_dist为半径的超球体内\n",
    "\n",
    "        temp_dist = abs(pivot[s] - target[s])  # 第s维上目标点与分割超平面的距离\n",
    "        if max_dist < temp_dist:  # 判断超球体是否与超平面相交\n",
    "            return result(nearest, dist, nodes_visited)  # 不相交则可以直接返回，不用继续判断\n",
    "\n",
    "        #----------------------------------------------------------------------\n",
    "        # 计算目标点与分割点的欧氏距离\n",
    "        temp_dist = sqrt(sum((p1 - p2)**2 for p1, p2 in zip(pivot, target)))\n",
    "\n",
    "        if temp_dist < dist:  # 如果“更近”\n",
    "            nearest = pivot  # 更新最近点\n",
    "            dist = temp_dist  # 更新最近距离\n",
    "            max_dist = dist  # 更新超球体半径\n",
    "\n",
    "        # 检查另一个子结点对应的区域是否有更近的点\n",
    "        temp2 = travel(further_node, target, max_dist)\n",
    "\n",
    "        nodes_visited += temp2.nodes_visited\n",
    "        if temp2.nearest_dist < dist:  # 如果另一个子结点内存在更近距离\n",
    "            nearest = temp2.nearest_point  # 更新最近点\n",
    "            dist = temp2.nearest_dist  # 更新最近距离\n",
    "\n",
    "        return result(nearest, dist, nodes_visited)\n",
    "\n",
    "    return travel(tree.root, point, float(\"inf\"))  # 从根节点开始递归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[7, 2]\n",
      "[5, 4]\n",
      "[2, 3]\n",
      "[4, 7]\n",
      "[9, 6]\n",
      "[8, 1]\n"
     ]
    }
   ],
   "source": [
    "data = [[2,3],[5,4],[9,6],[4,7],[8,1],[7,2]]\n",
    "kd = KdTree(data)\n",
    "preorder(kd.root)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 实验三 𝑘 值选择与模型复杂度及预测准确率的关系\n",
    "在二维空间中给出实例点，画出 𝑘 为1和2时的 𝑘 近邻法构成的空间划分，并对其进行比较，体会 𝑘 值选择与模型复杂度及预测准确率的关系。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1080x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from matplotlib.colors import ListedColormap\n",
    "\n",
    "data = np.array([[5, 12, 1], [6, 21, 0], [14, 5, 0], [16, 10, 0], [13, 19, 0], [13, 32, 1],\n",
    "                 [17, 27, 1], [18, 24, 1], [20, 20, 0], [23, 14, 1],[23, 25, 1], [23, 31, 1],\n",
    "                 [26, 8, 0], [30, 17, 1], [30, 26, 1], [34, 8, 0], [34, 19, 1], [37, 28, 1]])\n",
    "X_train = data[:, 0:2]\n",
    "y_train = data[:, 2]\n",
    "\n",
    "models = (KNeighborsClassifier(n_neighbors=1, n_jobs=-1), KNeighborsClassifier(n_neighbors=2, n_jobs=-1))\n",
    "models = (clf.fit(X_train, y_train) for clf in models)\n",
    "\n",
    "titles = ('K Neighbors with k=1', 'K Neighbors with k=2')\n",
    "\n",
    "fig = plt.figure(figsize=(15, 5))\n",
    "plt.subplots_adjust(wspace=0.4, hspace=0.4)\n",
    "\n",
    "X0, X1 = X_train[:, 0], X_train[:, 1]\n",
    "\n",
    "x_min, x_max = X0.min() - 1, X0.max() + 1\n",
    "y_min, y_max = X1.min() - 1, X1.max() + 1\n",
    "xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.2),\n",
    "                     np.arange(y_min, y_max, 0.2))\n",
    "\n",
    "for clf, title, ax in zip(models, titles, fig.subplots(1, 2).flatten()):\n",
    "    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])\n",
    "    Z = Z.reshape(xx.shape)\n",
    "    colors = ('red', 'green', 'lightgreen', 'gray', 'cyan')\n",
    "    cmap = ListedColormap(colors[:len(np.unique(Z))])\n",
    "    ax.contourf(xx, yy, Z, cmap=cmap, alpha=0.5)\n",
    "    ax.scatter(X0, X1, c=y_train, s=50, edgecolors='k', cmap=cmap, alpha=0.5)\n",
    "    ax.set_title(title)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 实验四 Kd 树临近点\n",
    "使用 𝑘𝑑 树求点 𝑥=(3,4.5)𝑇 的最近邻点。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x点的最近邻点是(2, 3)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from sklearn.neighbors import KDTree\n",
    "\n",
    "train_data = np.array([(2, 3), (5, 4), (9, 6), (4, 7), (8, 1), (7, 2)])\n",
    "tree = KDTree(train_data, leaf_size=2)\n",
    "dist, ind = tree.query(np.array([(3, 4.5)]), k=1)\n",
    "x1 = train_data[ind[0]][0][0]\n",
    "x2 = train_data[ind[0]][0][1]\n",
    "\n",
    "print(\"x点的最近邻点是({0}, {1})\".format(x1, x2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
